// X3DUMLv2Ctrl.cpp : Implementation of the CX3DUMLv2Ctrl ActiveX Control class.

#include "stdafx.h"
#include <typeinfo.h>
#include "X3DUMLv2.h"
#include "X3DUMLv2Ctrl.h"
#include "X3DUMLv2PropPage.h"


#ifdef _DEBUG
#define new DEBUG_NEW
#endif


IMPLEMENT_DYNCREATE(CX3DUMLv2Ctrl, COleControl)



// Message map

BEGIN_MESSAGE_MAP(CX3DUMLv2Ctrl, COleControl)
	ON_OLEVERB(AFX_IDS_VERB_PROPERTIES, OnProperties)
	ON_WM_CREATE()
	ON_WM_DESTROY()
	ON_WM_PAINT()
END_MESSAGE_MAP()



// Dispatch map

BEGIN_DISPATCH_MAP(CX3DUMLv2Ctrl, COleControl)
	DISP_FUNCTION_ID(CX3DUMLv2Ctrl, "FrameUpdate", dispidFrameUpdate, FrameUpdate, VT_EMPTY, VTS_NONE)
	DISP_FUNCTION_ID(CX3DUMLv2Ctrl, "AddStateView", dispidAddStateView, AddStateView, VT_BSTR, VTS_R8 VTS_R8 VTS_R8 VTS_R8 VTS_R8)
	DISP_FUNCTION_ID(CX3DUMLv2Ctrl, "AddTextView", dispidAddTextView, AddTextView, VT_BSTR, VTS_BSTR VTS_R8 VTS_R8 VTS_R8)
	DISP_FUNCTION_ID(CX3DUMLv2Ctrl, "RenderDiagram", dispidRenderDiagram, RenderDiagram, VT_EMPTY, VTS_NONE)
	DISP_FUNCTION_ID(CX3DUMLv2Ctrl, "AddPseudoStateView", dispidAddPseudoStateView, AddPseudoStateView, VT_BSTR, VTS_R8 VTS_R8 VTS_R8 VTS_R8 VTS_R8 VTS_BSTR)
	DISP_FUNCTION_ID(CX3DUMLv2Ctrl, "AddTransitionView", dispidAddTransitionView, AddTransitionView, VT_BSTR, VTS_BSTR)
	DISP_FUNCTION_ID(CX3DUMLv2Ctrl, "SetCurrentDiagram", dispidSetCurrentDiagram, SetCurrentDiagram, VT_BOOL, VTS_BSTR)
	DISP_FUNCTION_ID(CX3DUMLv2Ctrl, "ShowSplashScreen", dispidShowSplashScreen, ShowSplashScreen, VT_EMPTY, VTS_NONE)
	DISP_FUNCTION_ID(CX3DUMLv2Ctrl, "CurrentDiagramName", dispidCurrentDiagramName, CurrentDiagramName, VT_BSTR, VTS_NONE)
	DISP_FUNCTION_ID(CX3DUMLv2Ctrl, "SetOrCreateCurrentDiagram", dispidSetOrCreateCurrentDiagram, SetOrCreateCurrentDiagram, VT_BOOL, VTS_BSTR)
	DISP_FUNCTION_ID(CX3DUMLv2Ctrl, "CurrentDiagramFullyQualifiedName", dispidCurrentDiagramFullyQualifiedName, CurrentDiagramFullyQualifiedName, VT_BSTR, VTS_NONE)
	DISP_FUNCTION_ID(CX3DUMLv2Ctrl, "AddDiagram", dispidAddDiagram, AddDiagram, VT_BSTR, VTS_BSTR)
	DISP_FUNCTION_ID(CX3DUMLv2Ctrl, "SaveToOSG", dispidSaveToOSG, SaveToOSG, VT_EMPTY, VTS_BSTR)
	DISP_FUNCTION_ID(CX3DUMLv2Ctrl, "LinkElementToDiagram", dispidLinkElementToDiagram, LinkElementToDiagram, VT_BOOL, VTS_BSTR VTS_BSTR)
END_DISPATCH_MAP()



// Event map

BEGIN_EVENT_MAP(CX3DUMLv2Ctrl, COleControl)
END_EVENT_MAP()



// Property pages

// TODO: Add more property pages as needed.  Remember to increase the count!
BEGIN_PROPPAGEIDS(CX3DUMLv2Ctrl, 1)
	PROPPAGEID(CX3DUMLv2PropPage::guid)
END_PROPPAGEIDS(CX3DUMLv2Ctrl)



// Initialize class factory and guid

IMPLEMENT_OLECREATE_EX(CX3DUMLv2Ctrl, "X3DUMLV2.X3DUMLv2Ctrl.1",
	0x3ab0e140, 0xfc42, 0x4c0f, 0xaf, 0x69, 0xff, 0xa5, 0xe1, 0x48, 0, 0xe4)



// Type library ID and version

IMPLEMENT_OLETYPELIB(CX3DUMLv2Ctrl, _tlid, _wVerMajor, _wVerMinor)



// Interface IDs

const IID BASED_CODE IID_DX3DUMLv2 =
		{ 0xF282BA45, 0xF441, 0x43BE, { 0x98, 0x2, 0x83, 0x78, 0x1D, 0x8E, 0xC, 0xD6 } };
const IID BASED_CODE IID_DX3DUMLv2Events =
		{ 0x66E6282, 0xD4DD, 0x4442, { 0xBB, 0x2E, 0x4B, 0x2B, 0x8C, 0x3E, 0x72, 0xFC } };



// Control type information

static const DWORD BASED_CODE _dwX3DUMLv2OleMisc =
	OLEMISC_ACTIVATEWHENVISIBLE |
	OLEMISC_SETCLIENTSITEFIRST |
	OLEMISC_INSIDEOUT |
	OLEMISC_CANTLINKINSIDE |
	OLEMISC_RECOMPOSEONRESIZE;

IMPLEMENT_OLECTLTYPE(CX3DUMLv2Ctrl, IDS_X3DUMLV2, _dwX3DUMLv2OleMisc)



// CX3DUMLv2Ctrl::CX3DUMLv2CtrlFactory::UpdateRegistry -
// Adds or removes system registry entries for CX3DUMLv2Ctrl

BOOL CX3DUMLv2Ctrl::CX3DUMLv2CtrlFactory::UpdateRegistry(BOOL bRegister)
{
	// TODO: Verify that your control follows apartment-model threading rules.
	// Refer to MFC TechNote 64 for more information.
	// If your control does not conform to the apartment-model rules, then
	// you must modify the code below, changing the 6th parameter from
	// afxRegApartmentThreading to 0.

	if (bRegister)
		return AfxOleRegisterControlClass(
			AfxGetInstanceHandle(),
			m_clsid,
			m_lpszProgID,
			IDS_X3DUMLV2,
			IDB_X3DUMLV2,
			afxRegApartmentThreading,
			_dwX3DUMLv2OleMisc,
			_tlid,
			_wVerMajor,
			_wVerMinor);
	else
		return AfxOleUnregisterClass(m_clsid, m_lpszProgID);
}

class PickModeHandler : public osgGA::GUIEventHandler // forms need to not have tab stops (as that grabs the event before we get it)
{
    public:
        enum Modes
        {
            VIEW = 0,
            PICK
        };

        PickModeHandler():
            _mode(VIEW), //VIEW
            _activeDragger(0)
        {
        }        
        
        bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa,
                    osg::Object*, osg::NodeVisitor*)
        {
			//my code to set cursor (probably inefficient but it does the trick
			if(PICK == _mode){
				::SetCursor(LoadCursor(NULL, IDC_CROSS));
			} else
			{
				::SetCursor(LoadCursor(NULL, IDC_ARROW));
			}

            osgViewer::View* view = dynamic_cast<osgViewer::View*>(&aa);
            if (!view) return false;

            if (ea.getKey() == osgGA::GUIEventAdapter::KEY_Tab &&
                ea.getEventType() == osgGA::GUIEventAdapter::KEYDOWN &&
                _activeDragger == 0)
            {
                _mode = ! _mode;
            }
            
            if (VIEW == _mode) return false;

            switch (ea.getEventType())
            {
                case osgGA::GUIEventAdapter::PUSH:
                {
                    osgUtil::LineSegmentIntersector::Intersections intersections;

                    _pointer.reset();

                    if (view->computeIntersections(ea.getX(),ea.getY(),intersections))
                    {
                        _pointer.setCamera(view->getCamera());
                        _pointer.setMousePosition(ea.getX(), ea.getY());

                        for(osgUtil::LineSegmentIntersector::Intersections::iterator hitr = intersections.begin();
                            hitr != intersections.end();
                            ++hitr)
                        {
                            _pointer.addIntersection(hitr->nodePath, hitr->getLocalIntersectPoint());
                        }
                        for (osg::NodePath::iterator itr = _pointer._hitList.front().first.begin();
                             itr != _pointer._hitList.front().first.end();
                             ++itr)
                        {
                            osgManipulator::Dragger* dragger = dynamic_cast<osgManipulator::Dragger*>(*itr);
                            if (dragger)
                            {

                                dragger->handle(_pointer, ea, aa);
                                _activeDragger = dragger;
                                break;
                            }                   
                        }
                    }
                }
                case osgGA::GUIEventAdapter::DRAG:
                case osgGA::GUIEventAdapter::RELEASE:
                {
                    if (_activeDragger)
                    {
                        _pointer._hitIter = _pointer._hitList.begin();
                        _pointer.setCamera(view->getCamera());
                        _pointer.setMousePosition(ea.getX(), ea.getY());

                        _activeDragger->handle(_pointer, ea, aa);
                    }
                    break;
                }
        default:
            break;
            }

            if (ea.getEventType() == osgGA::GUIEventAdapter::RELEASE)
            {
                _activeDragger = 0;
                _pointer.reset();
            }

            return true;
        }
        
    private:
        unsigned int _mode;
        osgManipulator::Dragger* _activeDragger;
        osgManipulator::PointerInfo _pointer;
};

// CX3DUMLv2Ctrl::CX3DUMLv2Ctrl - Constructor
CX3DUMLv2Ctrl::CX3DUMLv2Ctrl()
{
	InitializeIIDs(&IID_DX3DUMLv2, &IID_DX3DUMLv2Events);
	// TODO: Initialize your control's instance data here.
	interactiveDiagram = new X3DUML::DiagramInterface();
}



// CX3DUMLv2Ctrl::~CX3DUMLv2Ctrl - Destructor
CX3DUMLv2Ctrl::~CX3DUMLv2Ctrl()
{
	// TODO: Cleanup your control's instance data here.
}



// CX3DUMLv2Ctrl::OnDraw - Drawing function
void CX3DUMLv2Ctrl::OnDraw(CDC* pdc, const CRect& rcBounds, const CRect& rcInvalid)
{
	if (!pdc)
		return;

	// TODO: Replace the following code with your own drawing code.
	//pdc->FillRect(rcBounds, CBrush::FromHandle((HBRUSH)GetStockObject(WHITE_BRUSH)));
	//pdc->Ellipse(rcBounds);
}

// CX3DUMLv2Ctrl::DoPropExchange - Persistence support
void CX3DUMLv2Ctrl::DoPropExchange(CPropExchange* pPX)
{
	ExchangeVersion(pPX, MAKELONG(_wVerMinor, _wVerMajor));
	COleControl::DoPropExchange(pPX);

	// TODO: Call PX_ functions for each persistent custom property.
}



// CX3DUMLv2Ctrl::OnResetState - Reset control to default state
void CX3DUMLv2Ctrl::OnResetState()
{
	COleControl::OnResetState();  // Resets defaults found in DoPropExchange

	// TODO: Reset any other control state here.
}



// CX3DUMLv2Ctrl message handlers
int CX3DUMLv2Ctrl::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	if (COleControl::OnCreate(lpCreateStruct) == -1)
		return -1;

	m_Filename = new char[255];

	RECT rect;
	GetWindowRect(&rect);

	///*WCHAR str[255];
	//swprintf(str, L"(%d,%d) - (%d,%d)", rect.left,rect.top,rect.right,rect.bottom);
	//::MessageBox(0, (LPCWSTR)str, L"Hint", MB_OK);*/

	//// Set window traits and gc
	m_Traits = new osg::GraphicsContext::Traits;
	osg::ref_ptr<osg::Referenced> windata = new osgViewer::GraphicsWindowWin32::WindowData( GetSafeHwnd() );
	m_Traits->x = 0;
	m_Traits->y = 0;
	m_Traits->width = rect.right - rect.left;
	m_Traits->height = rect.bottom - rect.top;
	m_Traits->windowDecoration = false;
	m_Traits->doubleBuffer = true;
	m_Traits->sharedContext = 0;
	m_Traits->setInheritedWindowPixelFormat = true;
	m_Traits->inheritedWindowData = windata;
	osg::GraphicsContext* gc = osg::GraphicsContext::createGraphicsContext( m_Traits.get() );
	gc->setClearColor( osg::Vec4f(0.2f, 0.2f, 0.6f, 1.0f) );
	gc->setClearMask( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

	//// Create camera
	osg::ref_ptr<osg::Camera> camera = new osg::Camera;
	camera->setGraphicsContext(gc);
	camera->setViewport( new osg::Viewport(m_Traits->x, m_Traits->y, m_Traits->width, m_Traits->height) );
	camera->setProjectionMatrixAsPerspective( 30.0f, (double)m_Traits->width/(double)m_Traits->height, 1.0f, 10000.0f );
	camera->setClearMask( GL_DEPTH_BUFFER_BIT );

	//// Create viewer
	m_Viewer = new osgViewer::Viewer;
	m_Viewer->setThreadingModel( osgViewer::Viewer::SingleThreaded );
	m_Viewer->setCamera( camera.get() );
	m_Viewer->setCameraManipulator( new osgGA::TrackballManipulator );

	//// Set root node of the scene
	m_Root = new osg::Group;
	// Have a root transition to rotate the entire coordinate space
	m_RootTrans = new osg::MatrixTransform;
	m_RootTrans->setMatrix(osg::Matrix::rotate(osg::inDegrees(-90.0f),1.0f,0.0f,0.0f));

	//// make the background white
	osg::ClearNode* backdrop = new osg::ClearNode;
	backdrop->setClearColor(osg::Vec4(1.0f,1.0f,1.0f,1.0f));
	//backdrop->setClearColor(osg::Vec4(0.9f,0.9f,0.9f,0.9f));
	m_Root->addChild(backdrop);
	m_Viewer->setSceneData( m_Root.get() );
	m_Viewer->realize();
	m_Viewer->addEventHandler(new PickModeHandler());
	m_Viewer->getCameraManipulator()->computeHomePosition();
	m_Viewer->getCameraManipulator()->home( 0.0 );

	// interactiveDiagram->AddDiagram("TOP");
	// Create a thread for the simulation loop
	//_beginthread(&RenderThread, 0, m_Viewer); 
	//LoadFile(L"D:\\OpenSceneGraph-Data\\cow.osg");
	//SplashScreen();
	return 0;
}

void CX3DUMLv2Ctrl::OnDestroy()
{
	COleControl::OnDestroy();

	m_Viewer->setDone( true );
	Sleep(100);
}

void CX3DUMLv2Ctrl::OnPaint()
{
	CPaintDC dc(this); // device context for painting
	// TODO: Add your message handler code here
	// Do not call COleControl::OnPaint() for painting messages
}

void CX3DUMLv2Ctrl::LoadFile(LPCTSTR lpszName) 
{
// Get string from client
	if ( !lpszName )
		return;
	//setlocale( LC_ALL, "chs" );
	wcstombs_s( NULL, m_Filename, 255, lpszName, 255 );

	// Remove loaded models
	if ( m_Root->getNumChildren() )
		m_Root->removeChildren( 0, m_Root->getNumChildren() );

	// Load a new model
	osg::ref_ptr<osg::Node> node;;
	osgDB::ReaderWriter::ReadResult rr = osgDB::Registry::instance()->readNode( m_Filename, osgDB::Registry::instance()->getOptions() );
	if ( rr.validNode() )
		node = rr.takeNode();
	if ( !node.valid() )
	{
		bool haserror = true;
		std::string errstr;

		switch( rr.status() )
		{
			case osgDB::ReaderWriter::ReadResult::FILE_NOT_FOUND: errstr = "File not found."; break;
			case osgDB::ReaderWriter::ReadResult::ERROR_IN_READING_FILE: errstr = "Error in reading file."; break;
			case osgDB::ReaderWriter::ReadResult::FILE_NOT_HANDLED: 
			{
				// Try to load again as a image file
				osg::ref_ptr<osg::Image> image = osgDB::readImageFile( m_Filename );
				if ( image.valid() )
				{
					node = createPlane( 5.0, 5.0, image.get() ).get();
					haserror = false;
				}
				else
					errstr = "File not supported."; 
				break;
			}
			default: errstr = "Fail to read file."; break;
		}

		if ( haserror )
		{
			::MessageBox(0, A2BSTR(errstr.c_str()), L"Error", MB_OK);
			return;
		}
	}
	node->setDataVariance( osg::Object::DYNAMIC );
	m_Root->addChild( node.get() );

	// Back to home position to see the whole scene
	m_Viewer->getCameraManipulator()->computeHomePosition();
	m_Viewer->getCameraManipulator()->home( 0.0 );
}

osg::ref_ptr<osg::Geode> CX3DUMLv2Ctrl::createPlane( float length, float width, osg::Image* image )
{
	// Vertices, normal and texture coordinates of the reference plane
	osg::ref_ptr<osg::Vec3Array> vec = new osg::Vec3Array;
	vec->resize( 4 );
	(*vec)[0] = osg::Vec3f(  length, 0, width )*0.5;
	(*vec)[1] = osg::Vec3f( -length, 0, width )*0.5;
	(*vec)[2] = osg::Vec3f( -length, 0,-width )*0.5;
	(*vec)[3] = osg::Vec3f(  length, 0,-width )*0.5;
	osg::ref_ptr<osg::Vec3Array> nor = new osg::Vec3Array;
	nor->push_back( osg::Vec3f( 0.0, -1.0, 0.0 ) );
	osg::ref_ptr<osg::Vec2Array> tex = new osg::Vec2Array;
	tex->push_back( osg::Vec2f(1.0, 1.0) );
	tex->push_back( osg::Vec2f(0.0, 1.0) );
	tex->push_back( osg::Vec2f(0.0, 0.0) );
	tex->push_back( osg::Vec2f(1.0, 0.0) );

	// Create the plane geometry & add it to a geode
	osg::ref_ptr<osg::Geometry> geo = new osg::Geometry;
	geo->setVertexArray( vec.get() );
	geo->setTexCoordArray( 0, tex.get() );
	geo->setNormalArray( nor.get() );
	geo->setNormalBinding( osg::Geometry::BIND_PER_PRIMITIVE_SET );
	geo->addPrimitiveSet( new osg::DrawArrays( osg::PrimitiveSet::QUADS, 0, 4 ) );
	osg::ref_ptr<osg::Geode> geode = new osg::Geode;
	geode->addDrawable( geo.get() );
	
	// Set the texture image
	osg::Texture2D* tex2d = new osg::Texture2D;
	tex2d->setImage( 0, image );
	osg::StateSet* stateset = geode->getOrCreateStateSet();
	stateset->setTextureAttributeAndModes( 0, tex2d, osg::StateAttribute::ON );

	return geode;
}
void CX3DUMLv2Ctrl::FrameUpdate(void)
{
	AFX_MANAGE_STATE(AfxGetStaticModuleState());
	if( !m_Viewer->done() )
	{
		m_Viewer->frame();
	}
}

BSTR CX3DUMLv2Ctrl::AddStateView(DOUBLE Width, DOUBLE Height, DOUBLE X, DOUBLE Y, DOUBLE Z)
{
	AFX_MANAGE_STATE(AfxGetStaticModuleState());
	
	CString strResult(interactiveDiagram->AddStateView(Width,Height,X,Y,Z).c_str());
	return strResult.AllocSysString();

	//interactiveDiagram->AddStateView(Width,Height,X,Y,Z);
}

BSTR CX3DUMLv2Ctrl::AddDiagram(LPCTSTR TextString)
{
	AFX_MANAGE_STATE(AfxGetStaticModuleState());

	//convert Windows String to Standard String
	std::wstring wString(TextString);
	std::string stdString(wString.begin(),wString.end());

	//interactiveDiagram->AddDiagram(stdString);
	CString strResult(interactiveDiagram->AddDiagram(stdString).c_str());
	return strResult.AllocSysString();
}

void CX3DUMLv2Ctrl::SaveToOSG(LPCTSTR TextString)
{
	AFX_MANAGE_STATE(AfxGetStaticModuleState());

	//convert Windows String to Standard String
	std::wstring wString(TextString);
	std::string stdString(wString.begin(),wString.end());

	osgDB::writeNodeFile( *m_Root.get() ,stdString);

}

BSTR CX3DUMLv2Ctrl::AddTextView(LPCTSTR TextString, DOUBLE X, DOUBLE Y, DOUBLE Z)
{
	AFX_MANAGE_STATE(AfxGetStaticModuleState());

	//convert Windows String to Standard String
	std::wstring wString(TextString);
	std::string stdString(wString.begin(),wString.end());

	//interactiveDiagram->AddTextView(stdString, X, Y, Z);
	CString strResult(interactiveDiagram->AddTextView(stdString, X, Y, Z).c_str());
	return strResult.AllocSysString();

}

void CX3DUMLv2Ctrl::RenderDiagram(void)
{
	AFX_MANAGE_STATE(AfxGetStaticModuleState());
	
	//process the diagram structure and return the visualisation to be added to the scene
	m_RootTrans->addChild(interactiveDiagram->RenderDiagram());
	m_Root->addChild(m_RootTrans.get());
	m_Root->addChild(interactiveDiagram->RenderWorldEdges());

	// Back to home position to see the whole scene
	m_Viewer->getCameraManipulator()->computeHomePosition();
	m_Viewer->getCameraManipulator()->home( 0.0 );
}

BSTR CX3DUMLv2Ctrl::AddPseudoStateView(DOUBLE Width, DOUBLE Height, DOUBLE X, DOUBLE Y, DOUBLE Z, LPCTSTR PseudoStateType)
{
	AFX_MANAGE_STATE(AfxGetStaticModuleState());

	//convert Windows String to Standard String
	std::wstring wString(PseudoStateType);
	std::string stdString(wString.begin(),wString.end());

	//interactiveDiagram->AddPseudoStateView(Width,Height,X,Y,Z,stdString);
	CString strResult(interactiveDiagram->AddPseudoStateView(Width,Height,X,Y,Z,stdString).c_str());
	return strResult.AllocSysString();

}

BSTR CX3DUMLv2Ctrl::AddTransitionView(LPCTSTR WayPointsCSVString)
{
	AFX_MANAGE_STATE(AfxGetStaticModuleState());

	//convert Windows String to Standard String
	std::wstring wString(WayPointsCSVString);
	std::string stdString(wString.begin(),wString.end());

	//interactiveDiagram->AddTransitionView(stdString);
	CString strResult(interactiveDiagram->AddTransitionView(stdString).c_str());
	return strResult.AllocSysString();
}

void CX3DUMLv2Ctrl::SplashScreen(void)
{
	interactiveDiagram->planeDepth = 200; // this is a small diagram so make it shallow
	std::string stateView;
	interactiveDiagram->SetOrCreateCurrentDiagram("Root.Top.");
	interactiveDiagram->AddStateView(400,300,-200,-150,0);
	//interactiveDiagram->AddTextView(interactiveDiagram->CurrentDiagramFullQualifiedName(),0,0,-100);
	interactiveDiagram->AddPseudoStateView(10,10,-100,-100,0,"Junction");
	stateView = interactiveDiagram->AddStateView(200,100,-100,-50,0);
	interactiveDiagram->AddTransitionView("-100,-100,0,-50,-50,0,");
	interactiveDiagram->AddTextView("X3D-UML",0,0,-2);

	//interactiveDiagram->AddTransitionView("50,50,0,50,100,0,-50,100,0,-50,50,0,");
	interactiveDiagram->SetOrCreateCurrentDiagram("Root.Top.SubDiagram1.");
	interactiveDiagram->AddStateView(240,50,150,-150,0);
	interactiveDiagram->AddTextView("Paul McIntosh",270,-125,-2);

	//interactiveDiagram->AddTransitionView("220,-100,100,220,0,0,100,0,0,");
	interactiveDiagram->LinkElementToDiagram(stateView, "Root.Top.SubDiagram1.");
	//LinkElementToDiagram(stateView, "Root.Top.SubDiagram1.")

}

VARIANT_BOOL CX3DUMLv2Ctrl::SetCurrentDiagram(LPCTSTR FullQualifiedName)
{
	AFX_MANAGE_STATE(AfxGetStaticModuleState());

	std::wstring wString(FullQualifiedName);
	std::string stdStringFullQualifiedName(wString.begin(),wString.end());

	if (interactiveDiagram->SetCurrentDiagram(stdStringFullQualifiedName))
	{
		return VARIANT_TRUE;
	}
	else
	{
		return VARIANT_FALSE;
	}
}

void CX3DUMLv2Ctrl::ShowSplashScreen(void)
{
	AFX_MANAGE_STATE(AfxGetAppModuleState());
	
	SplashScreen(); // add diagram elements for X3D-UML diagram

}

BSTR CX3DUMLv2Ctrl::CurrentDiagramName(void)
{
	AFX_MANAGE_STATE(AfxGetStaticModuleState());

	CString strResult(interactiveDiagram->CurrentDiagramName().c_str());
	return strResult.AllocSysString();
}

VARIANT_BOOL CX3DUMLv2Ctrl::SetOrCreateCurrentDiagram(LPCTSTR FullQualifiedName)
{
	AFX_MANAGE_STATE(AfxGetStaticModuleState());

	//convert Windows String to Standard String
	std::wstring wString(FullQualifiedName);
	std::string stdString(wString.begin(),wString.end());
	interactiveDiagram->SetOrCreateCurrentDiagram(stdString);

	//if (interactiveDiagram->SetOrCreateCurrentDiagram(stdString)){
	//	return VARIANT_TRUE;	
	//}
	//else{
	//	//Yikes this isn't good - should really throw an exception
	//	return VARIANT_FALSE;
	//};

	return VARIANT_TRUE;
}

BSTR CX3DUMLv2Ctrl::CurrentDiagramFullyQualifiedName(void)
{
	AFX_MANAGE_STATE(AfxGetStaticModuleState());

	CString strResult(interactiveDiagram->CurrentDiagramFullQualifiedName().c_str());
	return strResult.AllocSysString();
}


VARIANT_BOOL CX3DUMLv2Ctrl::LinkElementToDiagram(LPCTSTR elementFullyQualifiedName, LPCTSTR diagramFullyQualifiedName)
{
	AFX_MANAGE_STATE(AfxGetStaticModuleState());

	//convert Windows Strings to Standard Strings
	std::wstring elementwString(elementFullyQualifiedName);
	std::string elementString(elementwString.begin(),elementwString.end());	
	std::wstring diagramwString(diagramFullyQualifiedName);
	std::string diagramString(diagramwString.begin(),diagramwString.end());

	interactiveDiagram->LinkElementToDiagram(elementString,diagramString);

	// TODO: Add your dispatch handler code here

	return VARIANT_TRUE;
}
